Promise
Promise 是异步编程的一种解决方案,把传统的回调函数嵌套,变成了链式调用。感觉跟以前学过 RxJava 很像。
Promise 对象有以下两个特点:
- 对象的状态不受外界影响。Promise 对象代表一个异步操作,有3种状态: Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)。只有异步操作的结果可以决定当前是哪种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变就不会再变,任何时候都可以得到这个结果。一旦结果确定(成功或者失败),就不会再改变了。就算改变已经发生,再对 Promise 对象添加回调函数,也会立即得到这个结果。这跟传统的事件(Event)不同。
缺点:
无法取消。一旦新建就会立刻执行,无法取消。
基本用法
var promise = new Promise(function(resolve,reject){
// do some thing
if(/*异步操作成功*/){
resolve(value);
}else{
reject(error);
}
})
Promise 构造函数接受一个函数作为参数,改参数的两个参数分别是 resolve 和 reject。这是两个函数,有 JavaScript 引擎提供,不用自己部署。
resolve 函数是将 Promise 的状态变成“成功”,并将接收的参数传递出去。将会由 then 函数的第一参数(也是一个函数)接收到。
reject 函数是将 Promise 的状态变成“失败”,并将接收到的参数传递出去。将会由 then 函数的第二参数(也是一个函数)接收到。
一点疑惑
var promise= new Promise(function(resolve,reject){
console.log('Promise');
resolve();
});
promise.then(function(){
console.log('Resolved');
});
console.log('Hi!');
输出结果:
Promise
Hi!
Resolved
书中是这么解释的:Promise 新建后立即执行,所以首先输出 Promise 。然后,then 方法指定的回调函数将在当前脚本所有同步任务执行完成后才会执行,所以 Resolved 最后输出。
书中后面还补充了一点,resolve 是在 Promise 本轮事件循环的末尾执行,并总晚于本轮循环的同步任务。
还有一点比较有趣:
var p1 = new Promise(function(resolve,reject){
...
});
var p2 = new Promise(function(resolve,reject){
...
});
上面的代码中,p1 和 p2 都是 Promise 的实例,但是 p2 的 resolve 方法将 p1 作为参数,即一个异步操作的结果是返回另一个异步操作。这有点像 RxJava 里的流合并。
注意: 此时 p1 的状态就会传递给 p2 。也就是说,p1 的状态决定了 p2 的状态。如果 p1 的状态是 Pending ,那么 p2 就会等待 p1 的状态改变;如果 p1 的状态已经是 Resolved 或者 Reject ,那么 p2 的回调函数会立刻执行。
async
async 是 Generator 函数的语法糖。可以把异步变成同步。
使用很简单:
async function a() {
let b = await new Promise((resolve, reject) => {
setTimeout(() => {
let c=1;
console.log(c);
resolve(c);
},
2000)
});
return b + 1;
}
a().then((result) => {
console.log(result)
});
输出:
1
2
有以下几点要注意:
-
await 只能出现在 async 的函数内部,否则就会报错。
-
async 函数在执行到 await 时会暂停,等后面的 Promise(如果不是 Promise 对象,也会立即被转化为 马上 resolve 的 Promise )执行完成,执行完成 是指 调用了 resolve ,并把 resolve 的参数返回。
-
执行 async 函数时,会立即返回一个 Promise 对象。async 函数中,return 的值,会被当做 resolve 的参数。